<!-- 表格搜索组件 -->
<!-- 支持常用表单组件、自定义组件、插槽、校验、隐藏表单项 -->
<!-- 写法同 ElementPlus 官方文档组件，把属性写在 props 里面就可以了 -->
<template>
	<section class="art-search-bar art-custom-card" :class="{ 'is-expanded': isExpanded }" :style="artSearchBarStyle">
		<ElForm
			ref="formRef"
			:model="modelValue"
			:label-position="labelPosition"
			v-bind="{ ...$attrs }"
		>
			<ElRow class="search-form-row" :gutter="gutter">
				<ElCol
					v-for="(item, index) in visibleFormItems"
					:key="item.key"
					:xs="24"
					:sm="12"
					:md="8"
					:lg="item.span || span"
					:xl="item.span || span"
				>
					<ElFormItem
						:label="item.label"
						:prop="item.key"
						:label-width="item.label ? item.labelWidth || labelWidth : undefined"
					>
						<slot :name="item.key" :item="item" :modelValue="modelValue">
							<component
								:is="getComponent(item)"
								v-model="modelValue[item.key]"
								v-bind="getProps(item)"
							>
								<!-- 精准和模糊搜索切换 -->
								<template v-if="item.precisionAndAmbiguity" #append>
									<ElSelect v-model="item.key"
										  style="width: 110px"
										  @change="(value: any) => handlePrecisionAndAmbiguityChange(value, index)">
										<ElOption
											:label="t('common.precision')"
											:value="item.precisionAndAmbiguity[0]"
										>
										</ElOption>
										<ElOption
											:label="t('common.ambiguity')"
											:value="item.precisionAndAmbiguity[1]"
										>
										</ElOption>
									</ElSelect>
								</template>
								<!-- 下拉选择 -->
								<template
									v-if="item.type === 'select' && getProps(item)?.options">
									<el-option
										v-for="option in getProps(item).options"
										v-bind="option"
										:key="option.value"
									/>
								</template>

								<!-- 复选框组 -->
								<template
									v-if="item.type === 'checkboxgroup' && getProps(item)?.options">
									<el-checkbox
										v-for="option in getProps(item).options"
										v-bind="option"
										:key="option.value"
									/>
								</template>

								<!-- 单选框组 -->
								<template
									v-if="item.type === 'radiogroup' && getProps(item)?.options">
									<el-radio
										v-for="option in getProps(item).options"
										v-bind="option"
										:key="option.value"
									/>
								</template>

								<!-- 动态插槽支持 -->
								<template v-for="(slotFn, slotName) in getSlots(item)"
									  :key="slotName" #[slotName]>
									<component :is="slotFn"/>
								</template>

							</component>
						</slot>
					</ElFormItem>
				</ElCol>
				<ElCol :xs="24" :sm="24" :md="span" :lg="span" :xl="span" class="action-column">
					<div class="action-buttons-wrapper" :style="actionButtonsStyle">
						<div class="form-buttons">
							<el-button v-if="showReset" class="reset-button"
								   @click="handleReset" v-ripple>
								{{ t('table.searchBar.reset') }}
							</el-button>
							<el-button
								v-if="showSearch"
								type="primary"
								class="search-button"
								@click="handleSearch"
								v-ripple
								:disabled="disabledSearch"
							>
								{{ t('table.searchBar.search') }}
							</el-button>
						</div>
						<div v-if="shouldShowExpandToggle" class="filter-toggle"
						     @click="toggleExpand">
							<span>{{ expandToggleText }}</span>
							<div class="icon-wrapper">
								<el-icon>
									<ArrowUpBold v-if="isExpanded"/>
									<ArrowDownBold v-else/>
								</el-icon>
							</div>
						</div>
					</div>
				</ElCol>
			</ElRow>
		</ElForm>
	</section>
</template>

<script setup lang="ts">
import {ArrowDownBold, ArrowUpBold} from '@element-plus/icons-vue'
import {useWindowSize} from '@vueuse/core'
import {useI18n} from 'vue-i18n'
import type {FormInstance} from 'element-plus'
import {delObjEmptyVal} from '@utils/helper'

defineOptions({name: 'ArtSearchBar'})

const componentMap = {
	input: ElInput, // 输入框
	number: ElInputNumber, // 数字输入框
	select: ElSelect, // 选择器
	switch: ElSwitch, // 开关
	checkbox: ElCheckbox, // 复选框
	checkboxgroup: ElCheckboxGroup, // 复选框组
	radiogroup: ElRadioGroup, // 单选框组
	date: ElDatePicker, // 日期选择器
	daterange: ElDatePicker, // 日期范围选择器
	datetime: ElDatePicker, // 日期时间选择器
	datetimerange: ElDatePicker, // 日期时间范围选择器
	rate: ElRate, // 评分
	slider: ElSlider, // 滑块
	cascader: ElCascader, // 级联选择器
	timepicker: ElTimePicker, // 时间选择器
	timeselect: ElTimeSelect, // 时间选择
	treeselect: ElTreeSelect // 树选择器
}

const {width} = useWindowSize()
const {t} = useI18n()
const isMobile = computed(() => width.value < 500)

const formInstance = useTemplateRef<FormInstance>('formRef')
const backItems = ref<any>([])

// 表单项配置
export interface SearchFormItem {
	/** 表单项的唯一标识 */
	key: string
	/** 表单项的标签文本 */
	label: string
	/** 初始值 */
	initValue?: any
	/** 精准和模糊搜索切换 */
	precisionAndAmbiguity?: any
	/** 是否转时间戳 */
	toTimestamp?: boolean
	/** 表单项标签的宽度，会覆盖 Form 的 labelWidth */
	labelWidth?: string | number
	/** 表单项类型，可以是预定义的字符串类型或自定义组件 */
	type: keyof typeof componentMap | string | (() => VNode)
	/** 是否隐藏该表单项 */
	hidden?: boolean
	/** 表单项占据的列宽，基于24格栅格系统 */
	span?: number
	/** 选项数据，用于 select、checkbox-group、radio-group 等 */
	options?: Record<string, any>
	/** 传递给表单项组件的属性 */
	props?: Record<string, any>
	/** 表单项的插槽配置 */
	slots?: Record<string, (() => any) | undefined>
	/** 表单项的占位符文本 */
	placeholder?: string
	/** 更多属性配置请参考 ElementPlus 官方文档 */
}

// 表单配置
interface SearchBarProps {
	/** 表单数据 */
	items: SearchFormItem[]
	/** 每列的宽度（基于 24 格布局） */
	span?: number
	/** 表单控件间隙 */
	gutter?: number
	/** 展开/收起 */
	isExpand?: boolean
	/** 默认是否展开（仅在 showExpand 为 true 且 isExpand 为 false 时生效） */
	defaultExpanded?: boolean
	/** 表单域标签的位置 */
	labelPosition?: 'left' | 'right' | 'top'
	/** 文字宽度 */
	labelWidth?: string | number
	/** 是否需要展示，收起 */
	showExpand?: boolean
	/** 按钮靠左对齐限制（表单项小于等于该值时） */
	buttonLeftLimit?: number
	/** 是否显示重置按钮 */
	showReset?: boolean
	/** 是否显示搜索按钮 */
	showSearch?: boolean
	/** 是否禁用搜索按钮 */
	disabledSearch?: boolean
}

const props = withDefaults(defineProps<SearchBarProps>(), {
	items: () => [],
	span: 6,
	gutter: 12,
	isExpand: false,
	labelPosition: 'right',
	labelWidth: '70px',
	showExpand: true,
	defaultExpanded: false,
	buttonLeftLimit: 2,
	showReset: true,
	showSearch: true,
	disabledSearch: false
})

interface SearchBarEmits {
	(e: 'search', params: Record<string, any>): void

	(e: 'reset', params: Record<string, any>): void
}

const emit = defineEmits<SearchBarEmits>()

const modelValue = ref<any>({})


/**
 * 是否展开状态
 */
const isExpanded = ref(props.defaultExpanded)

const rootProps = ['label', 'labelWidth', 'key', 'type', 'hidden', 'span', 'slots']

const getProps = (item: SearchFormItem) => {
	if (item.props) return item.props
	const props = {...item}
	rootProps.forEach((key) => delete (props as Record<string, any>)[key])
	return props
}

// 获取插槽
const getSlots = (item: SearchFormItem) => {
	if (!item.slots) return {}
	const validSlots: Record<string, () => any> = {}
	Object.entries(item.slots).forEach(([key, slotFn]) => {
		if (slotFn) {
			validSlots[key] = slotFn
		}
	})
	return validSlots
}

// 组件
const getComponent = (item: SearchFormItem) => {
	const {type} = item
	if (type && typeof item.type !== 'string') return type
	// type不传递、默认使用 input
	return componentMap[type as keyof typeof componentMap] || componentMap['input']
}

/**
 * 可见的表单项
 */
const visibleFormItems = computed(() => {
	const filteredItems = props.items.filter((item) => !item.hidden)
	const shouldShowLess = !props.isExpand && !isExpanded.value
	if (shouldShowLess) {
		const maxItemsPerRow = Math.floor(24 / props.span) - 1
		return filteredItems.slice(0, maxItemsPerRow)
	}
	return filteredItems
})

/**
 * 是否应该显示展开/收起按钮
 */
const shouldShowExpandToggle = computed(() => {
	const filteredItems = props.items.filter((item) => !item.hidden)
	return (
		!props.isExpand && props.showExpand && filteredItems.length > Math.floor(24 / props.span) - 1
	)
})

/**
 * 展开/收起按钮文本
 */
const expandToggleText = computed(() => {
	return isExpanded.value ? t('table.searchBar.collapse') : t('table.searchBar.expand')
})

/**
 * 操作按钮样式
 */
const actionButtonsStyle = computed(() => ({
	'justify-content': isMobile.value ? 'flex-end'
		: props.items.filter((item) => !item.hidden).length <= props.buttonLeftLimit ? 'flex-start' : 'flex-end',
	'margin-top': (props.labelPosition === 'top' && !isMobile.value) ? '40px' : '0'
}))

const artSearchBarStyle =  computed(() => ({
	'padding': props.labelPosition === 'top' ? '0 20px 0' : '15px 20px 0',
}))

/**
 * 切换展开/收起状态
 */
const toggleExpand = () => {
	isExpanded.value = !isExpanded.value
}

/**
 * 处理重置事件
 */
const handleReset = () => {
	// 重置表单字段（UI 层）
	formInstance.value?.resetFields()
	handleSetModelValue()
	let filterData: any = {...modelValue.value}
	delObjEmptyVal(filterData)
	props.items.forEach((item) => {
		if (item.toTimestamp && filterData[item.key]) {
			if (typeof filterData[item.key] === 'object') {
				filterData[item.key] = {
					start: parseInt(((new Date(filterData[item.key][0]).getTime()) / 1000).toString()),
					end: parseInt(((new Date(filterData[item.key][1]).getTime()) / 1000).toString())
				}
			}else{
				filterData[item.key] = parseInt(((new Date(filterData[item.key]).getTime()) / 1000).toString())
			}
		}
	})
	emit('reset', filterData)
}

/**
 * 处理搜索事件
 */
const handleSearch = () => {
	let filterData: any = {...modelValue.value}
	delObjEmptyVal(filterData)
	props.items.forEach((item) => {
		if (item.toTimestamp && filterData[item.key]) {
			if (typeof filterData[item.key] === 'object') {
				filterData[item.key] = {
					start: parseInt(((new Date(filterData[item.key][0]).getTime()) / 1000).toString()),
					end: parseInt(((new Date(filterData[item.key][1]).getTime()) / 1000).toString())
				}
			}else{
				filterData[item.key] = parseInt(((new Date(filterData[item.key]).getTime()) / 1000).toString())
			}
		}
	})
	emit('search', filterData)
}

/**
 * 处理精准和模糊搜索切换
 */
const handlePrecisionAndAmbiguityChange = (value: any, index: any) => {
	let backValue: any = undefined
	props.items[index].precisionAndAmbiguity.forEach((item: any) => {
		if (modelValue.value[item]) backValue = modelValue.value[item]
		if (modelValue.value.hasOwnProperty(item)) delete modelValue.value[item]
	})
	const temp: any = {}
	temp[value] = backValue
	Object.assign(modelValue.value, temp)
}

/**
 * 处理设置modelValue
 */
const handleSetModelValue = () =>{
	const newModelValue: any = {}
	backItems.value.forEach((item: any, index: any) => {
		newModelValue[item.key] = item.initValue ?? undefined
		props.items[index].key = item.key
	})
	modelValue.value = newModelValue
}

watch(() => props.items, (newValue: any) => {
	backItems.value = JSON.parse(JSON.stringify(newValue))
	handleSetModelValue()
}, {immediate: true})



defineExpose({
	ref: formInstance,
	validate: (...args: any[]) => formInstance.value?.validate(...args),
	reset: handleReset
})

// 解构 props 以便在模板中直接使用
const {span, gutter, labelPosition, labelWidth} = toRefs(props)
</script>

<style lang="scss" scoped>
.art-search-bar {
	padding: 15px 20px 0;
	background-color: var(--art-main-bg-color);
	border-radius: calc(var(--custom-radius) / 2 + 2px);

	:deep(.el-form-item--label-top .el-form-item__label) {
		margin-left: 3px !important;
		margin-bottom: 2px !important;
	}

	.search-form-row {
		display: flex;
		flex-wrap: wrap;
	}

	.action-column {
		flex: 1;
		max-width: 100%;

		.action-buttons-wrapper {
			display: flex;
			flex-wrap: wrap;
			align-items: center;
			justify-content: flex-end;
			margin-bottom: 12px;
		}

		.form-buttons {
			display: flex;
			gap: 8px;
		}

		.filter-toggle {
			display: flex;
			align-items: center;
			margin-left: 10px;
			line-height: 32px;
			color: var(--main-color);
			cursor: pointer;
			transition: color 0.2s ease;

			&:hover {
				color: var(--ElColor-primary);
			}

			span {
				font-size: 14px;
				user-select: none;
			}

			.icon-wrapper {
				display: flex;
				align-items: center;
				margin-left: 4px;
				font-size: 14px;
				transition: transform 0.2s ease;
			}
		}
	}
}

// 响应式优化
@media (width <= 768px) {
	.art-search-bar {
		padding: 16px 16px 0;

		.action-column {
			.action-buttons-wrapper {
				flex-direction: column;
				gap: 8px;
				align-items: stretch;

				.form-buttons {
					justify-content: center;
				}

				.filter-toggle {
					justify-content: center;
					margin-left: 0;
				}
			}
		}
	}
}
</style>
